package org.zhangkun.jmsg.core.network.filetransport;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;

import org.zhangkun.jmsg.bean.DataPack;
import org.zhangkun.jmsg.bean.DataPackage;
import org.zhangkun.jmsg.bean.DataUnPack;
import org.zhangkun.jmsg.bean.User;
import org.zhangkun.jmsg.ui.swing.FileTransportViewDialog;
import org.zhangkun.jmsg.util.FileUtil;
import org.zhangkun.jmsg.util.GlobalVar;

public class ReceiveFiles extends FileTransport {
	private ArrayList<String> createDirs = new ArrayList<String>();
	private ArrayList<String> createFiles = new ArrayList<String>();
	/**
	 * 
	 * @param dup
	 * @param frm
	 */

	protected DataUnPack dup;

	protected boolean isOverlay = true;

	protected String savePath;

	public ReceiveFiles(DataUnPack dup, User user) {
		super(user, ACCEPT);
		this.dup = dup;
		parseMsg();
	}

	public ArrayList<String> getCreateDirs() {
		return createDirs;
	}

	public ArrayList<String> getCreateFiles() {
		return createFiles;
	}

	/**
	 * 接收文件
	 */
	private boolean getFile(Socket socket, FileMsgPackage fmp, String path) {
		if (FileUtil.isExists(path))
			if (!isOverlay)
				return true;
			else
				FileUtil.delFile(path);
		DataPack dp = dup.getDataPack();
		dp.setDataType(DataPackage.IPMSG_GETFILEDATA);
		dp.setMsg(fmp.packToRequest());
		try {
			os.write(dp.getData());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			// e.printStackTrace();
			setError("数据传送错误。");
			return false;
		}
		return saveFile(path + fmp.getFileName(), fmp.getFileSize());
	}

	/**
	 * 接收文件夹
	 */
	private boolean getFolder(Socket socket, FileMsgPackage fmp, String pa) {
		try {
			DataPack dp = dup.getDataPack();
			dp.setDataType(DataPackage.IPMSG_GETDIRFILES);
			dp.setMsg(fmp.packToRequest());
			os.write(dp.getData());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			setError("数据传送错误。");
			return false;
		}
		return saveFolder(pa);
	}

	public String getSavePath() {
		return savePath;
	}

	private String getStr() {
		int i = 0;
		try {
			while (is.read(buffer, i, 1) != -1) {
				if (buffer[i] == (char) ':')
					break;
				i++;
			}
			return new String(buffer, 0, i, "gbk");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	public boolean isCancleNow() {
		return cancleNow;
	}

	public boolean isOverlay() {
		return isOverlay;
	}

	public void parseMsg() {
		String[] fs = dup.getMsg().split("\\a");
		long pd = Long.parseLong(dup.getDataID());
		for (String s : fs) {
			FileMsgPackage fmp = new FileMsgPackage();
			fmp.setPackageID(pd + "");
			fmp.unpackToResponseMsg(s);
			allSize += fmp.getFileSize();
			fmps.add(fmp);
		}
		Collections.sort(fmps);
		fmpSize = fmps.size();
	}

	/**
	 * 开始传送文件
	 */
	public void run() {
		FileTransportViewDialog.addFileTransport(this);
		status = STATUS_RUNNING;
		// System.out.println("Start ");
		allReadSize = 0;
		for (int i = 0; i < fmps.size(); i++) {
			try {
				socket = new Socket(InetAddress.getByName(dup
						.getSenderHostAddres()), 2425);
				is = socket.getInputStream();
				os = socket.getOutputStream();
				FileMsgPackage fmp = fmps.get(i);
				index = i;
				currentTransportReadSize = 0;
				currentTransportSize = fmp.getFileSize();
				if (fmp.getFileMsgType() == 1) {
					if (!getFile(socket, fmp, savePath))
						break;
				} else if (getFolder(socket, fmp, savePath))
					break;
			} catch (UnknownHostException e) {
				// TODO Auto-generated catch block
				// e.printStackTrace();
				setError("无法连接至对方主机。");
			} catch (IOException e) {
				// TODO Auto-generated catch block
				setError("数据传送错误。");
				// e.printStackTrace();
			} finally {
				if (socket != null)
					try {
						socket.close();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
			}
		}
		if (status == STATUS_RUNNING)
			status = STATUS_FINISH;
		// System.out.println("Finish ");
	}

	private boolean saveFile(String path, long size) {
		// System.out.println("saveFile " + path);
		boolean flag = true;
		if (FileUtil.isExists(path))
			if (!isOverlay)
				return false;
			else
				FileUtil.delFile(path);
		fileNum++;
		FileOutputStream fos = null;
		currentFileReadLength = 0;
		currentFileLength = size;
		currentFileName = path;
		try {
			try {
				fos = new FileOutputStream(path);
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				setError("文件：" + path + "不存在！");
				return false;
			}
			int length = (int) (buffer.length > size ? size : buffer.length);
			while (currentFileReadLength != size) {
				// System.out.println("length " + length + " readLength"
				// + currentReadLength + " currentFileLength "
				// + currentFileLength);
				try {
					length = is.read(buffer, 0, length);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					// e.printStackTrace();
					FileUtil.delFile(path);
					setError("连接中断！");
					flag = false;
					break;
				}

				if (length == -1 && currentFileReadLength != size) {
					System.out.println("数据读取错误!(文件大小:" + size + "读取大小:"
							+ currentFileReadLength + ")");
					flag = false;
					break;
				}

				currentFileReadLength += length;
				allReadSize += length;
				currentTransportReadSize += length;
				try {
					fos.write(buffer, 0, length);
					fos.flush();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					setError("文件：" + path + "写入错误！");
					FileUtil.delFile(path);
					flag = false;
					break;
				}
				length = buffer.length;
				if (currentFileReadLength + length >= size) {
					length = (int) (size - currentFileReadLength);
				}
				if (cancleNow) {
					setError("用户中断。");
					status = STATUS_USER_CANCEL;
					flag = false;
					break;
				}
			}
		} finally {
			if (fos != null)
				try {
					fos.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}
		if (flag == false) {
			FileUtil.delFile(path);
		} else
			createFiles.add(path);
		return flag;
	}

	private boolean saveFolder(String path) {
		if (!FileUtil.isExists(path))
			if (!FileUtil.createDir(path)) {
				setError(path + "创建失败。");
				return false;
			} else
				createDirs.add(path);
		int d = 0;
		do {
			String head = getStr();
			String fileName = null;
			long fileSize = 0;
			int type = -1;
			if (head == null || head.length() == 0) {
				setError("数据传输错误，头信息读取失败。Head=" + head);
				return false;
			}
			int length = Integer.parseInt(head, 16) - head.length() - 1;
			if (length < 0) {
				setError("数据传输错误，头数据错误。");
				return false;
			}
			try {
				is.read(buffer, 0, length);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				setError("读取数据错误。");
				return false;
			}
			String[] info = null;
			try {
				info = new String(buffer, 0, length,
						GlobalVar.TRANSPORT_ENCODING).split(":");
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				setError("读取时编码解析错误。");
				return false;
			}
			// System.out.println(head + ":" + (new String(buffer, 0, length)));
			if (info.length < 3) {
				// System.out.println("读取解析错误。");
				try {
					setError("读取解析错误。"
							+ (new String(buffer, 0, length,
									GlobalVar.TRANSPORT_ENCODING)));
				} catch (UnsupportedEncodingException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				return false;
			}
			fileName = info[0];
			fileSize = Long.parseLong(info[1], 16);
			type = Integer.parseInt(info[2], 16);
			switch (type) {
			case (int) DataPackage.IPMSG_FILE_REGULAR:
				if (!saveFile(path + fileName, fileSize))
					return false;
				break;
			case (int) DataPackage.IPMSG_FILE_DIR:
				path += fileName + "/";
				if (!FileUtil.isExists(path))
					if (!FileUtil.createDir(path)) {
						setError("路径：" + path + "无法创建！");
						return false;
					} else
						createDirs.add(path);
				d++;
				break;
			case (int) DataPackage.IPMSG_FILE_RETPARENT:
				path = FileUtil.getParentDir(path);
				d--;
				break;
			default:
				setError("命令错误。");
				return false;
			}
		} while (d > 0);
		return true;
	}

	public void setAllSize(long allSize) {
		this.allSize = allSize;
	}

	public void setCancleNow(boolean cancleNow) {
		this.cancleNow = cancleNow;
	}

	public void setCreateDirs(ArrayList<String> createDirs) {
		this.createDirs = createDirs;
	}

	public void setCreateFiles(ArrayList<String> createFiles) {
		this.createFiles = createFiles;
	}

	public void setCurrentFileLength(int currentFileLength) {
		this.currentFileReadLength = currentFileLength;
	}

	public void setCurrentReadLength(int currentReadLength) {
		this.currentFileReadLength = currentReadLength;
	}

	public void setDup(DataUnPack dup) {
		this.dup = dup;
	}

	public void setOverlay(boolean isOverlay) {
		this.isOverlay = isOverlay;
	}

	public void setSavePath(String savePath) {
		if (!savePath.matches(".*[\\/\\\\]$"))
			this.savePath = savePath + "/";
		else
			this.savePath = savePath;
	}

}
